#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>

#define RingBufferNum 10
#ifndef NULL
#define NULL (void*)0
#endif

/*	环形缓冲区
 *	最多可以创建RingBufferNum(10)个确定的BufferType_t类型的环形缓冲区
 *	使用过程如下
 *	包含源文件和头文件到你的项目
 * 	bd0 = RingBufferInit(bufferlen,sizeof(data_tpye));
 *	RingBufferExit(bd0);
 *	err = int SendToRingBuffer(int bd, void* data, int cover);
 *	err = GetFromRingBuffer(bd0, &readdata);
 */
struct RingBuffer_t
{
	int BufferDescription;	//环形缓冲区描述符
	size_t pBuffer;			//环形缓冲区数组的地址
	int iDataLen;			//每个数据的长度
	int iBufferNum;			//环形缓冲区存放数据的数量
	int iRead;				//写位置
	int iWrite;				//读位置
	int iIscover;        	//是否可以覆盖
};

static int IsBufferEmpty(int bd);
static int IsBufferFull(int bd);
static int AssignBufferDescription(void);
/* 存有RingBuffer_t指针的数组 */
static struct RingBuffer_t* g_pRingBuffer[RingBufferNum] = { NULL };

/* private function */
/* 判断环形缓冲区是否为空 */
static int IsBufferEmpty(int bd)
{
	return (g_pRingBuffer[bd]->iRead == g_pRingBuffer[bd]->iWrite);
}
/* 判断环形缓冲区是否为满*/
static int IsBufferFull(int bd)
{
	return (g_pRingBuffer[bd]->iRead == ((g_pRingBuffer[bd]->iWrite + 1) % g_pRingBuffer[bd]->iBufferNum));
}
/*
 * @return 环形缓冲区描述符,无空间返回-1
 */
static int AssignBufferDescription(void)
{
	int index = 0;
	for (index = 0; index < RingBufferNum; index++)
	{
		if (g_pRingBuffer[index] == NULL)
			return index;
	}
	return -1;
}
/* public function */
int RingBufferInit(int buffer_num, int data_len, int iscover)
{
	int buffernum;
	int BufferDescription = AssignBufferDescription();
	if (BufferDescription >= 0)
	{
		g_pRingBuffer[BufferDescription] = (struct RingBuffer_t*)malloc(sizeof(struct RingBuffer_t));		//每个数组存放一个环形缓冲区结构体的地址
		g_pRingBuffer[BufferDescription]->iBufferNum = buffer_num + 1;							//多分配一个空间
		g_pRingBuffer[BufferDescription]->iDataLen = data_len;
		buffernum = g_pRingBuffer[BufferDescription]->iBufferNum * g_pRingBuffer[BufferDescription]->iDataLen;
		g_pRingBuffer[BufferDescription]->pBuffer = (size_t)malloc(buffernum);
		g_pRingBuffer[BufferDescription]->iRead = 0;
		g_pRingBuffer[BufferDescription]->iWrite = 0;
		g_pRingBuffer[BufferDescription]->iIscover = iscover;
	}
	return BufferDescription;
}
int RingBufferExit(int bd)
{
	if (g_pRingBuffer[bd] == NULL)
	{
		printf("RingBufferExit,g_pRingBuffer[%d] == NULL\n", bd);
		return -1;
	}
	free((void*)g_pRingBuffer[bd]->pBuffer);
	free((void*)g_pRingBuffer[bd]);
	g_pRingBuffer[bd] = NULL;
	return 0;
}

int SendToRingBuffer(int bd, void* data)
{
	if (g_pRingBuffer[bd] == NULL)
	{
		printf("SendToRingBuffer,g_pRingBuffer[%d] == NULL\n", bd);
		return -1;
	}
	if (!IsBufferFull(bd))
	{
		void* pPos = (void*)(g_pRingBuffer[bd]->pBuffer + (ptrdiff_t)(g_pRingBuffer[bd]->iWrite * g_pRingBuffer[bd]->iDataLen));
		memcpy(pPos, (void*)data, g_pRingBuffer[bd]->iDataLen);
		g_pRingBuffer[bd]->iWrite = (g_pRingBuffer[bd]->iWrite + 1) % g_pRingBuffer[bd]->iBufferNum;
		return 0;
	}
	else if (g_pRingBuffer[bd]->iIscover)
	{
		void* pPos = (void*)(g_pRingBuffer[bd]->pBuffer + (ptrdiff_t)(g_pRingBuffer[bd]->iWrite * g_pRingBuffer[bd]->iDataLen));
		memcpy(pPos, (void*)data, g_pRingBuffer[bd]->iDataLen);
		g_pRingBuffer[bd]->iWrite = (g_pRingBuffer[bd]->iWrite + 1) % g_pRingBuffer[bd]->iBufferNum;
		g_pRingBuffer[bd]->iRead = (g_pRingBuffer[bd]->iRead + 1) % g_pRingBuffer[bd]->iBufferNum;
		return 0;
	}
	printf("This ringbuffer[%d] is full\n", bd);
	return -1;
}
int GetFromRingBuffer(int bd, void* data)
{
	if (g_pRingBuffer[bd] == NULL)
	{
		printf("GetFromRingBuffer,g_pRingBuffer[%d] == NULL\n", bd);
		return -1;
	}
	if (!IsBufferEmpty(bd))
	{
		void* pPos = (void*)(g_pRingBuffer[bd]->pBuffer + (ptrdiff_t)(g_pRingBuffer[bd]->iRead * g_pRingBuffer[bd]->iDataLen));
		memcpy((void*)data, pPos, g_pRingBuffer[bd]->iDataLen);
		g_pRingBuffer[bd]->iRead = (g_pRingBuffer[bd]->iRead + 1) % g_pRingBuffer[bd]->iBufferNum;
		return 0;
	}
	printf("This ringbuffer[%d] is empty\n", bd);
	return -1;
}

